﻿#include "GAF_MoveAction.h"
#include "GAF_Platform.h"

namespace GAF
{
	MoveAction::MoveAction() :
		ATTRIB(Speed)(50),
		ATTRIB(AddSpeed)(0),
		ATTRIB(MaxSpeed)(0),
		m_nSpeed(0),
		m_nTimes(0),
		m_nWay(1),
		m_isAtFPS(false),
		m_ttLast(0),
		m_fRemanent(0.0),
		m_isAgain(false),
		m_atPath(NULL),
		m_nPathLen(0),
		m_nCur(0)
	{
	}

	MoveAction::~MoveAction()
	{
		GAF_DELETE_ARY(m_atPath);
		GAF_DELETE_ARY(m_Intent.atPaths);
	}

	void MoveAction::AtFPS(bool isAtFPS)
	{
		m_isAtFPS = isAtFPS;
	}

	void MoveAction::SetIntent(ActionIntent* pIntent)
	{
		GAF_CHECK(pIntent != NULL);

		MoveIntent* _pMoveIntent = (MoveIntent*)pIntent;

		GAF_DELETE_ARY(m_Intent.atPaths);
// 		m_Intent.Reset();
		_MEMCPY(&m_Intent, _pMoveIntent, sizeof(MoveIntent));
		m_Intent.CopyControl(pIntent);
// 		m_Intent.isHasCurPos = _pMoveIntent->isHasCurPos;
// 		m_Intent.nPathNum = _pMoveIntent->nPathNum;
// 		m_Intent.nMode = _pMoveIntent->nMode;
// 		m_Intent.nTimes = _pMoveIntent->nTimes;
		if(_pMoveIntent->atPaths != NULL)
		{
			m_Intent.atPaths = GAF_NEW_ARY(Point, _pMoveIntent->nPathNum);
			_MEMCPY(m_Intent.atPaths, _pMoveIntent->atPaths, sizeof(Point) * _pMoveIntent->nPathNum);
		}

		CreatPathLine();

		m_nCur = 0;
		m_nWay = 1;
		m_nTimes = 0;
		GetHostGraphics()->SetLocation(m_atPath[m_nCur]);
	}

	void MoveAction::MoveTo(Point at)
	{
		MoveTo(at.nX, at.nY);
	}

	void MoveAction::MoveTo(int nX, int nY)
	{
		MoveIntent _intent;
		Point _atPathTo;
		_atPathTo.Set(nX, nY);

		_intent.nPathNum = 1;
// 		_MEMCPY(_intent.atPaths, &_atPathTo
		_intent.atPaths = &_atPathTo;

		SetIntent(&_intent);

		m_nSpeed = ATTRIB(Speed);
		GetHostGraphics()->SetLocation(m_atPath[m_nCur]);

		Play();
	}

	void MoveAction::MoveAgain()
	{
		GAF_CHECK(m_atPath != NULL);

		Stop();

		m_nCur = 0;
		m_nWay = 1;
		m_nTimes = 0;

		m_nSpeed = ATTRIB(Speed);
		GetHostGraphics()->SetLocation(m_atPath[m_nCur]);

		Play();
	}

	bool MoveAction::OnUpdate(TimeTicks ttUsed)
	{
		if(!OnMoveAct())
			return false;

		if(m_nSpeed <= 0)
			return false;

		if(m_isAgain)
		{
			MoveAgain();
			return true;
		}

		static bool isReturn;
		isReturn = true;
		
		m_nCur += m_nWay * Move();

		// 加速度
		m_nSpeed += ATTRIB(AddSpeed);
		if(ATTRIB(MaxSpeed) > 0)
		{
			if(m_nSpeed > ATTRIB(MaxSpeed))
				m_nSpeed = ATTRIB(MaxSpeed);
		}

		// m_nCur 要在路径范围之内
		while(m_nCur < 0 || m_nCur > (int)m_nPathLen)
		{
			if(m_nWay > 0)
			{ // 正方向
				m_nTimes++;
				if(m_nTimes >= (int)m_Intent.nTimes)
				{ // 完成一定次数
					m_nCur = m_nPathLen - 1;
					if(GetLoop())
					{ // 为循环，再次运行
						m_isAgain = true;
					}
					else
					{ // 为单次，结束
						isReturn = false;
					}
				}
				else
				{ // 没完成一定次数，根据运动模式决定
					switch(m_Intent.amMode)
					{
					case ACTION_AGAIN:
						m_nCur = m_nCur - m_nPathLen;
						break;
					case ACTION_RETURN:
						m_nWay = -1;
						m_nCur = (m_nPathLen - 1) - (m_nCur - m_nPathLen);
						break;
					}
				}
			}
			else if(m_nWay < 0)
			{ // 反方向
				m_nWay = 1;
				m_nCur = (m_nCur >= 0 ? m_nCur : -m_nCur) - 1;
			}
		}

		GetHostGraphics()->SetLocation(GAF_ARG_POINT(m_atPath[m_nCur]));

		return isReturn;
	}

	bool MoveAction::OnPlay(Bundle* pParam)
	{
		GAF_CHECK_R(m_atPath != NULL, false);

		if(m_isAgain || GetState() != PLAYER_PLAY)
		{
			m_ttLast = GAF_pTHEPLATFORM->GetTimeTicks();

			if(GetState() == PLAYER_STOP)
			{
				m_nSpeed = ATTRIB(Speed);
				m_fRemanent = 0.0;
				m_isAgain = false;
			}
		}

		return true;
	}

	bool MoveAction::OnStop()
	{
		m_nCur = 0;
		m_nSpeed = ATTRIB(Speed);

		return true;
	}

	int MoveAction::Move()
	{
		if(m_isAtFPS)
			return m_nSpeed;

		// 每毫秒
		static float s_fSpeed;
		s_fSpeed = (float)m_nSpeed / (float)1000;

		// 当前时间
		static TimeTicks ttNow;
		ttNow = GAF_pTHEPLATFORM->GetTimeTicks();
		
		// 应移动距离
		static float fSpace;
		fSpace = (float)(ttNow - m_ttLast) * s_fSpeed + (float)m_fRemanent;
		m_fRemanent = fSpace - (int)fSpace;

		m_ttLast = ttNow;

		// 移动
		return (int)fSpace;
	}

	void MoveAction::CreatPathLine()
	{
		if(m_Intent.nPathNum <= 0)
			return;

		if(m_atPath != NULL)
			GAF_DELETE_ARY(m_atPath);

		int _nLineNum = m_Intent.nPathNum - 1; // 路径数量

		m_nPathLen = 0;

		// 创建每一条路径的线路
		Point** _patLines = NULL;
		int* _nLens = NULL;
		if(_nLineNum > 0)
		{
			// 多路径点
			_patLines = GAF_NEW_ARY(Point*, _nLineNum);
			_nLens = GAF_NEW_ARY(int, _nLineNum);
			for(int i = 0; i < _nLineNum; i++)
			{
				_nLens[i] = CreatLine(m_Intent.atPaths[i], m_Intent.atPaths[i + 1]);
				_patLines[i] = GAF_NEW_ARY(Point, _nLens[i]);
				m_nPathLen += CreatLine(m_Intent.atPaths[i], m_Intent.atPaths[i + 1], _patLines[i]);
			}
			m_nPathLen -= _nLineNum - 1; // 删除每段线路的头尾重复点
		}
		else
		{
			// 只有一个路径点
			_patLines = GAF_NEW_ARY(Point*, 1);
			_nLens = GAF_NEW_ARY(int, 1);
			_nLens[0] = 1;
			_patLines[0] = GAF_NEW_ARY(Point, 1);
			_MEMCPY(_patLines[0], m_Intent.atPaths, sizeof(Point));
			m_nPathLen = 1;
		}

		// 创建当前点到第一路径点的线路
		if(m_Intent.isHasCurPos)
		{ /// 计算长度
			int nLenCur = CreatLine(GetHostGraphics()->GetLocation(), m_Intent.atPaths[0]);
			m_nPathLen += nLenCur - 1;
		}
		/// 创建线路
		m_atPath = GAF_NEW_ARY(Point, m_nPathLen);
		_MEMSET(m_atPath, 0, sizeof(Point) * m_nPathLen);
		int _nID = 0;
		if(m_Intent.isHasCurPos)
		{
			_nID = CreatLine(GetHostGraphics()->GetLocation(), m_Intent.atPaths[0], m_atPath) - 1;
		}

		// 复制每一条路径的线路
		int _i = 0;
		do
		{
			_MEMCPY(m_atPath + _nID, _patLines[_i], sizeof(Point) * _nLens[_i]);
			_nID += _nLens[_i] - 1;
			GAF_DELETE_ARY(_patLines[_i]);
		}while(++_i < _nLineNum);
		GAF_DELETE_ARY(_patLines);
		GAF_DELETE_ARY(_nLens);
	}

	int MoveAction::CreatLine(Point& atStart, Point& atEnd, Point* patPath)
	{
		int _nLen = GAF_MAX_NUM(abs(atStart.nX - atEnd.nX), abs(atStart.nY - atEnd.nY)) + 1;

		if(patPath != NULL)
		{
			int _nIndex = 0;
			int _x, _y;
			int _dx, _dy;
			int _incx, _incy;
			int _balance;
			int _i = 0;

			if (atEnd.nX >= atStart.nX)
			{
				_dx = atEnd.nX - atStart.nX;
				_incx = 1;
			}
			else
			{
				_dx = atStart.nX - atEnd.nX;
				_incx = -1;
			}
			if (atEnd.nY >= atStart.nY)
			{
				_dy = atEnd.nY - atStart.nY;
				_incy = 1;
			}
			else
			{
				_dy = atStart.nY - atEnd.nY;
				_incy = -1;
			}
			_x = atStart.nX;
			_y = atStart.nY;
			if (_dx >= _dy)
			{
				_dy <<= 1;
				_balance = _dy - _dx;
				_dx <<= 1;
				while (_x != atEnd.nX)
				{
					patPath[_nIndex].nX = _x;
					patPath[_nIndex].nY = _y;
					_nIndex++;
					if (_balance >= 0)
					{
						_y += _incy;
						_balance -= _dx;
					}
					_balance += _dy;
					_x += _incx;
					_i++;
				}
				patPath[_nIndex].nX = _x;
				patPath[_nIndex].nY = _y;
				_nIndex++;
			}
			else
			{
				_dx <<= 1;
				_balance = _dx - _dy;
				_dy <<= 1;
				while (_y != atEnd.nY)
				{
					patPath[_nIndex].nX = _x;
					patPath[_nIndex].nY = _y;
					_nIndex++;
					if (_balance >= 0)
					{
						_x += _incx;
						_balance -= _dy;
					}
					_balance += _dx;
					_y += _incy;
					_i++;
				}
				patPath[_nIndex].nX = _x;
				patPath[_nIndex].nY = _y;
				_nIndex++;
			}
		}

		return _nLen;
	}
}